import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedelta
import random
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
import warnings

warnings.filterwarnings('ignore')  # 忽略警告信息

# 设置中文显示
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False  # 解决负号显示问题

def generate_shopping_data(num_orders=5000):
    """生成模拟的618购物数据"""
    # 商品类别
    categories = ['电子产品', '服装鞋帽', '家居用品', '美妆个护', '食品饮料', '母婴用品', '图书音像']

    # 品牌列表
    brands = {
        '电子产品': ['苹果', '华为', '小米', '三星', '索尼', '戴尔', '联想'],
        '服装鞋帽': ['耐克', '阿迪达斯', '优衣库', 'ZARA', 'H&M', '李宁', '安踏'],
        '家居用品': ['宜家', '无印良品', '小米有品', '网易严选', '全友', '顾家', '索菲亚'],
        '美妆个护': ['兰蔻', '雅诗兰黛', 'SK-II', '迪奥', '香奈儿', '资生堂', '欧莱雅'],
        '食品饮料': ['可口可乐', '百事可乐', '蒙牛', '伊利', '雀巢', '旺旺', '康师傅'],
        '母婴用品': ['惠氏', '雅培', '美赞臣', '帮宝适', '好奇', '贝亲', '好孩子'],
        '图书音像': ['中信', '人民文学', '机械工业', '电子工业', '新星', '磨铁', '读客']
    }

    # 生成日期范围（6月1日至6月20日）
    start_date = datetime(2025, 6, 1)
    end_date = datetime(2025, 6, 20)
    date_range = [start_date + timedelta(days=i) for i in range((end_date - start_date).days + 1)]

    # 用户ID
    user_ids = [f'user_{i:05d}' for i in range(1, 1001)]

    # 生成订单数据
    orders = []
    for _ in range(num_orders):
        order_id = f'order_{random.randint(1000000, 9999999)}'
        user_id = random.choice(user_ids)
        order_date = random.choice(date_range)
        category = random.choice(categories)
        brand = random.choice(brands[category])
        product_name = f'{brand}{random.choice(["旗舰", "经典", "新款", "超值", "限量"])}款{category}'

        # 价格和数量的分布
        if category == '电子产品':
            price = round(np.random.normal(3000, 1500), 2)
            price = max(500, price)
            quantity = random.randint(1, 3)
        elif category == '服装鞋帽':
            price = round(np.random.normal(300, 150), 2)
            price = max(30, price)
            quantity = random.randint(1, 5)
        elif category == '家居用品':
            price = round(np.random.normal(500, 300), 2)
            price = max(50, price)
            quantity = random.randint(1, 3)
        elif category == '美妆个护':
            price = round(np.random.normal(200, 100), 2)
            price = max(20, price)
            quantity = random.randint(1, 5)
        elif category == '食品饮料':
            price = round(np.random.normal(50, 30), 2)
            price = max(5, price)
            quantity = random.randint(1, 10)
        elif category == '母婴用品':
            price = round(np.random.normal(150, 80), 2)
            price = max(30, price)
            quantity = random.randint(1, 5)
        else:  # 图书音像
            price = round(np.random.normal(50, 25), 2)
            price = max(10, price)
            quantity = random.randint(1, 8)

        amount = price * quantity

        # 促销活动影响
        if order_date.day in [1, 16, 18, 20]:  # 大促日
            discount = random.uniform(0.5, 0.9)
            amount = round(amount * discount, 2)
            promotion = f'618大促{int((1 - discount) * 10)}折'
        elif order_date.day in [6, 11, 13, 15, 17, 19]:  # 小促日
            discount = random.uniform(0.8, 0.95)
            amount = round(amount * discount, 2)
            promotion = f'限时{int((1 - discount) * 100)}折'
        else:  # 普通日
            if random.random() < 0.3:  # 30%概率有小优惠
                discount = random.uniform(0.9, 0.98)
                amount = round(amount * discount, 2)
                promotion = f'普通优惠{int((1 - discount) * 100)}折'
            else:
                promotion = '无促销'

        # 支付方式
        payment_method = random.choices(
            ['支付宝', '微信支付', '银行卡', '京东支付', '现金'],
            weights=[0.45, 0.35, 0.15, 0.04, 0.01]
        )[0]

        # 用户地区
        region = random.choices(
            ['华东', '华南', '华北', '西南', '西北', '东北', '华中'],
            weights=[0.3, 0.2, 0.15, 0.15, 0.08, 0.07, 0.05]
        )[0]

        orders.append({
            '订单ID': order_id,
            '用户ID': user_id,
            '订单日期': order_date,
            '商品类别': category,
            '品牌': brand,
            '商品名称': product_name,
            '单价': price,
            '数量': quantity,
            '金额': amount,
            '促销活动': promotion,
            '支付方式': payment_method,
            '地区': region
        })

    return pd.DataFrame(orders)

def analyze_shopping_data(df):
    """分析购物数据并生成可视化图表"""
    print("数据基本信息: ")
    df.info()

    # 1. 每日销售额趋势
    daily_sales = df.groupby(df['订单日期'].dt.date)['金额'].sum().reset_index()
    plt.figure(figsize=(12, 6))
    plt.plot(daily_sales['订单日期'], daily_sales['金额'], marker='o')
    plt.title('618期间每日销售额趋势')
    plt.xlabel('日期')
    plt.ylabel('销售额(元)')
    plt.grid(True, linestyle='--', alpha=0.7)
    plt.xticks(rotation=45)
    for x, y in zip(daily_sales['订单日期'], daily_sales['金额']):
        plt.annotate(f'{y:.0f}', (x, y), textcoords='offset points',
                     xytext=(0, 5), ha='center', rotation=45)
    plt.tight_layout()
    plt.savefig('daily_sales.png')
    plt.close()

    # 2. 商品类别销售占比
    category_sales = df.groupby('商品类别')['金额'].sum().reset_index()
    plt.figure(figsize=(10, 8))
    plt.pie(category_sales['金额'], labels=category_sales['商品类别'],
            autopct='%1.1f%%', startangle=90, shadow=True,
            wedgeprops={'edgecolor': 'w', 'linewidth': 1})
    plt.title('各商品类别销售金额占比')
    plt.axis('equal')
    plt.tight_layout()
    plt.savefig('category_sales.png')
    plt.close()

    # 3. 不同促销活动的销售额对比
    promotion_sales = df.groupby('促销活动')['金额'].sum().reset_index()
    plt.figure(figsize=(10, 6))
    sns.barplot(x='促销活动', y='金额', data=promotion_sales)
    plt.title('不同促销活动的销售额对比')
    plt.xlabel('促销活动')
    plt.ylabel('销售额(元)')
    for i, v in enumerate(promotion_sales['金额']):
        plt.text(i, v + 10000, f'{v:.0f}', ha='center')
    plt.tight_layout()
    plt.savefig('promotion_sales.png')
    plt.close()

    # 4. 各地区销售分布
    region_sales = df.groupby('地区')['金额'].sum().reset_index()
    plt.figure(figsize=(10, 6))
    sns.barplot(x='地区', y='金额', data=region_sales,
                hue='地区', palette='viridis', legend=False)
    plt.title('各地区销售金额分布')
    plt.xlabel('地区')
    plt.ylabel('销售额(元)')
    for i, v in enumerate(region_sales['金额']):
        plt.text(i, v + 10000, f'{v:.0f}', ha='center')
    plt.tight_layout()
    plt.savefig('region_sales.png')
    plt.close()

    # 5. 支付方式分布
    payment_distribution = df['支付方式'].value_counts().reset_index()
    payment_distribution.columns = ['支付方式', '订单数量']
    plt.figure(figsize=(10, 6))
    sns.barplot(x='支付方式', y='订单数量', data=payment_distribution)
    plt.title('支付方式分布')
    plt.xlabel('支付方式')
    plt.ylabel('订单数量')
    for i, v in enumerate(payment_distribution['订单数量']):
        plt.text(i, v + 10, f'{v}', ha='center')
    plt.tight_layout()
    plt.savefig('payment_distribution.png')
    plt.close()

    # 6. 商品类别与销售金额的关系（箱线图）
    plt.figure(figsize=(12, 6))
    sns.boxplot(x='商品类别', y='金额', data=df)
    plt.title('商品类别与销售金额关系')
    plt.xlabel('商品类别')
    plt.ylabel('销售金额(元)')
    plt.xticks(rotation=30)
    plt.tight_layout()
    plt.savefig('category_amount_boxplot.png')
    plt.close()

    # 7. 每日订单数量与平均金额
    daily_orders = df.groupby(df['订单日期'].dt.date).agg(
        订单数量=('订单ID', 'count'),
        平均金额=('金额', 'mean')
    ).reset_index()

    fig, ax1 = plt.subplots(figsize=(12, 6))
    ax2 = ax1.twinx()

    ax1.bar(daily_orders['订单日期'], daily_orders['订单数量'], color='skyblue', alpha=0.6)
    ax1.set_xlabel('日期')
    ax1.set_ylabel('订单数量', color='skyblue')
    ax1.tick_params(axis='y', labelcolor='skyblue')

    ax2.plot(daily_orders['订单日期'], daily_orders['平均金额'], color='red', marker='o')
    ax2.set_ylabel('平均金额(元)', color='red')
    ax2.tick_params(axis='y', labelcolor='red')

    plt.title('每日订单数量与平均金额对比')
    plt.xticks(rotation=45)
    plt.tight_layout()
    plt.savefig('daily_orders_avg_amount.png')
    plt.close()

    # 8. 热门品牌销售额TOP10
    brand_sales = df.groupby('品牌')['金额'].sum().reset_index()
    top_brands = brand_sales.sort_values('金额', ascending=False).head(10)

    plt.figure(figsize=(12, 6))
    sns.barplot(x='品牌', y='金额', data=top_brands,
                hue='品牌', palette='magma', legend=False)
    plt.title('热门品牌销售额TOP10')
    plt.xlabel('品牌')
    plt.ylabel('销售额(元)')
    for i, v in enumerate(top_brands['金额']):
        plt.text(i, v + 10000, f'{v:.0f}', ha='center')
    plt.tight_layout()
    plt.savefig('top_brands.png')
    plt.close()

    print('数据可视化分析完成！图表已保存至当前目录。')

    # 返回分析结果
    return {
        '每日销售额': daily_sales,
        '商品类别销售占比': category_sales,
        '促销活动销售额': promotion_sales,
        '地区销售分布': region_sales,
        '支付方式分布': payment_distribution,
        '热门品牌TOP10': top_brands
    }

def build_region_prediction_model(df):
    """构建预测用户地区的机器学习模型"""
    print("\n正在构建地区预测模型...")
    # 特征工程
    # 1. 提取用户特征
    user_features = df.groupby('用户ID').agg(
        总订单数=('订单ID', 'count'),
        总消费金额=('金额', 'sum'),
        平均订单金额=('金额', 'mean'),
        最大订单金额=('金额', 'max'),
        最小订单金额=('金额', 'min'),
        购买不同商品类别数=('商品类别', 'nunique'),
        购买不同品牌数=('品牌', 'nunique')
    ).reset_index()

    # 2. 提取用户最常购买的商品类别和品牌
    user_top_category = df.groupby('用户ID')['商品类别'].agg(lambda x: x.value_counts().index[0]).reset_index()
    user_top_brand = df.groupby('用户ID')['品牌'].agg(lambda x: x.value_counts().index[0]).reset_index()

    # 3. 提取用户最常使用的支付方式
    user_top_payment = df.groupby('用户ID')['支付方式'].agg(lambda x: x.value_counts().index[0]).reset_index()

    # 4. 提取用户最活跃的时间段（按促销活动类型）
    user_top_promotion = df.groupby('用户ID')['促销活动'].agg(lambda x: x.value_counts().index[0]).reset_index()

    # 5. 合并所有用户特征
    user_features = user_features.merge(user_top_category, on='用户ID')
    user_features = user_features.merge(user_top_brand, on='用户ID')
    user_features = user_features.merge(user_top_payment, on='用户ID')
    user_features = user_features.merge(user_top_promotion, on='用户ID')

    # 6. 添加用户地区（目标变量）
    user_region = df.groupby('用户ID')['地区'].agg(lambda x: x.value_counts().index[0]).reset_index()
    user_features = user_features.merge(user_region, on='用户ID')

    # 准备建模数据
    X = user_features.drop(['用户ID', '地区'], axis=1)
    y = user_features['地区']
    # 划分训练集和测试集
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    # 定义预处理步骤
    numeric_features = X.select_dtypes(include=['int64', 'float64']).columns.tolist()
    categorical_features = X.select_dtypes(include=['object']).columns.tolist()

    preprocessor = ColumnTransformer(
        transformers=[
            ('num', StandardScaler(), numeric_features),
            ('cat', OneHotEncoder(), categorical_features)
        ]
    )

    # 构建完整的模型管道
    model = Pipeline(steps=[('preprocessor', preprocessor),
                            ('classifier', LogisticRegression(max_iter=1000, random_state=42))])

    # 训练模型
    model.fit(X_train, y_train)

    # 预测
    y_pred = model.predict(X_test)

    # 评估模型
    accuracy = accuracy_score(y_test, y_pred)
    print(f"\n模型准确率: {accuracy:.2f}")

    # 打印分类报告
    print("\n分类报告:")
    print(classification_report(y_test, y_pred))

    # 可视化混淆矩阵
    plt.figure(figsize=(10, 8))
    cm = confusion_matrix(y_test, y_pred)
    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
                xticklabels=model.classes_, yticklabels=model.classes_)
    plt.title('地区预测模型混淆矩阵')
    plt.xlabel('预测地区')
    plt.ylabel('实际地区')
    plt.tight_layout()
    plt.savefig('region_prediction_confusion_matrix.png')
    plt.close()

    # 查看模型参数
    print("\n模型参数:")
    print("类别:", model.classes_)

    # 获取特征名称
    ohe = model.named_steps['preprocessor'].named_transformers_['cat']
    feature_names = numeric_features + list(ohe.get_feature_names_out(categorical_features))

    # 获取逻辑回归系数
    coef = model.named_steps['classifier'].coef_

    # 为每个类别打印前5个重要特征
    for i, class_name in enumerate(model.classes_):
        print(f"\n{class_name} 地区的重要特征:")
        class_coef = coef[i]
        top_features_idx = np.argsort(np.abs(class_coef))[-5:][::-1]  # 取绝对值最大的5个特征
        for idx in top_features_idx:
            print(f"  {feature_names[idx]}: {class_coef[idx]:.4f}")

    return model, user_features

if __name__ == "__main__":
    # 生成模拟数据
    print("正在生成模拟的618购物数据...")
    shopping_data = generate_shopping_data(num_orders=10000)

    # 保存数据到CSV
    shopping_data.to_csv('618_shopping_data.csv', index=False, encoding='utf-8-sig')
    print(f"数据已保存至 '618_shopping_data.csv', 共{len(shopping_data)}条记录。")

    # 分析数据
    print("\n开始分析数据...")
    analysis_results = analyze_shopping_data(shopping_data)

    # 构建机器学习模型
    model, user_features = build_region_prediction_model(shopping_data)

    # 保存用户特征数据
    user_features.to_csv('user_features.csv', index=False, encoding='utf-8-sig')
    print(f"\n用户特征数据已保存至 'user_features.csv'")

    # 打印关键分析结果
    print("\n关键分析结果：")
    print("1. 销售额最高的日期：")
    top_sales_date = analysis_results['每日销售额'].sort_values('金额', ascending=False).iloc[0]
    print(f"  {top_sales_date['订单日期']}: {top_sales_date['金额']:.2f}元")

    print("\n2. 销售额最高的商品类别：")
    top_category = analysis_results['商品类别销售占比'].sort_values('金额', ascending=False).iloc[0]
    print(f"  {top_category['商品类别']}: {top_category['金额']:.2f}元，占比{top_category['金额'] / analysis_results['商品类别销售占比']['金额'].sum() * 100:.1f}%")

    print("\n3. 最有效的促销活动：")
    top_promotion = analysis_results['促销活动销售额'].sort_values('金额', ascending=False).iloc[0]
    print(f"  {top_promotion['促销活动']}: {top_promotion['金额']:.2f}元")

    print("\n4. 销售额最高的地区：")
    top_region = analysis_results['地区销售分布'].sort_values('金额', ascending=False).iloc[0]
    print(f"  {top_region['地区']}: {top_region['金额']:.2f}元")

    print("\n5. 最受欢迎的支付方式：")
    top_payment = analysis_results['支付方式分布'].sort_values('订单数量', ascending=False).iloc[0]
    print(f"  {top_payment['支付方式']}: {top_payment['订单数量']}单")

    print("\n6. 销售额最高的品牌: ")
    top_brand = analysis_results['热门品牌TOP10'].sort_values('金额', ascending=False).iloc[0]
    print(f"  {top_brand['品牌']}: {top_brand['金额']:.2f}元")